﻿//-----------------------------------------------------------------------
// <copyright file="TfsSubmitConfig.cs" company="Microsoft Corporation">
//     Copyright (c) Microsoft Corporation 2011. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Internal.TeamFoundationServer.Submit
{
    using System.Configuration;
    using System.Diagnostics;
    using System.IO;
    using System.Reflection;

    /// <summary>
    /// ConfigurationReader class.
    /// </summary>
    internal class TfsSubmitConfig
    {
        #region config constants

        /// <summary>
        /// indicate if CodeReview feature is Enabled.
        /// </summary>
        private const string CodeReviewEnabledConfig = "CodeReviewEnabled";

        /// <summary>
        /// indicate if Shelve feature is Enabled.
        /// </summary>
        private const string ShelveEnabledConfig = "ShelveEnabled";

        /// <summary>
        /// indicate if ValidateChanges feature is Enabled.
        /// </summary>
        private const string ValidateChangesEnabledConfig = "ValidateChangesEnabled";
    
        /// <summary>
        /// indicate if SubmitChanges feature is Enabled
        /// </summary>
        private const string SubmitChangesEnabledConfig = "SubmitChangesEnabled";

        /// <summary>
        /// Indicate if Check-in, Shelve, Un-Shelve related buttons should be disable in Visual Studio.
        /// </summary>
        private const string DisableTfsButtonsConfig = "DisableTFSButton";

        /// <summary>
        /// Indicate if code coverage should be validated before check-in.
        /// </summary>
        private const string ValidateCodeCoverageConfig = "ValidateCodeCoverage";

        /// <summary>
        /// Indicate what state the work item should be to allow check-in. 
        /// Work Items with different state than this one will not be available to be selected
        /// </summary>
        private const string ValidWorkItemStateConfig = "ValidWorkItemState";

        /// <summary>
        /// Indicate what state the work item should go after check-in.
        /// </summary>
        private const string ResolvedWorkItemStateConfig = "ResolvedWorkItemState";

        /// <summary>
        /// Indicate Resolution field name on WorkItem template.
        /// </summary>
        private const string ResolutionStateFieldNameConfig = "ResolutionStateFieldName";

        /// <summary>
        /// Indicate Resolution value the work item will be set after check-in
        /// </summary>
        private const string ResolutionStateValueConfig = "ResolutionStateValue";

        /// <summary>
        /// Indicate Build Version field name on WorkItem template.
        /// </summary>
        private const string BuildVersionFieldNameConfig = "BuildVersionFieldName";

        /// <summary>
        /// Indicate Fix description field name on WorkItem template.
        /// </summary>
        private const string FixDescriptionFieldNameConfig = "FixDescriptionFieldName";

        /// <summary>
        /// Indicate WorkItem field Names on WorkItem template.
        /// </summary>
        private const string WorkItemFieldNamesConfig = "WorkItemFieldNames";

        /// <summary>
        /// Indicate WorkItem field Values on WorkItem template.
        /// </summary>
        private const string WorkItemFieldValuesConfig = "WorkItemFieldValues";

        /// <summary>
        /// Indicate the name of the build definition that manages the build version.
        /// </summary>
        private const string BuildDefinitionNameConfig = "BuildDefinitionName";

        /// <summary>
        /// Mail Domain name.
        /// </summary>
        private const string MailDomainConfig = "MailDomain";

        /// <summary>
        /// Domain name.
        /// </summary>
        private const string DomainFullyQualifiedNameConfig = "DomainFullyQualifiedName";

        /// <summary>
        /// SMTP server.
        /// </summary>
        private const string SmtpServerConfig = "SmtpServer";

        /// <summary>
        /// Recipients check-in email should be sent to.
        /// </summary>
        private const string CheckinEmailsAliasesConfig = "CheckinEmailsAliases";

        /// <summary>
        /// Recipients code reviewers aliases should be sent to.
        /// </summary>
        private const string CodeReviewAliasesConfig = "CodeReviewAliases";

        /// <summary>
        /// Malevich Server Name.
        /// </summary>
        private const string MalevichServerNameConfig = "MalevichServerName";

        /// <summary>
        /// Malevich Grant Vote Permission Stored Procedure Name.
        /// </summary>
        private const string GrantVotePermissionProcNameConfig = "GrantVotePermissionProcName";

        /// <summary>
        /// Malevich command line tool.
        /// </summary>
        private const string MalevichToolConfig = "MalevichTool";

        /// <summary>
        /// Required number of code reviewers.
        /// </summary>
        private const string RequiredReviewersConfig = "RequiredReviewers";

        #endregion

        #region fields

        /// <summary>
        /// CodeReview feature is Enabled.
        /// </summary>
        private static bool codeReviewEnabled;

        /// <summary>
        /// Shelve feature is Enabled.
        /// </summary>
        private static bool shelveEnabled;

        /// <summary>
        /// ValidateChanges feature is Enabled.
        /// </summary>
        private static bool validateChangesEnabled;

        /// <summary>
        /// SubmitChanges feature is Enabled
        /// </summary>
        private static bool submitChangesEnabled;

        /// <summary>
        /// TFS buttons are disabled ?
        /// </summary>
        private static bool disableTfsButtonsEnabled;

        /// <summary>
        /// Validate CodeCoverage ?
        /// </summary>
        private static bool validateCodeCoverage;

        /// <summary>
        /// Valid Work Item.
        /// </summary>
        private static string validWorkItemState;

        /// <summary>
        /// Resolved WorkItem State.
        /// </summary>
        private static string resolvedWorkItemState;

        /// <summary>
        /// Resolution State FieldName.
        /// </summary>
        private static string resolutionStateFieldName;
        
        /// <summary>
        /// Resolution State Value.
        /// </summary>
        private static string resolutionStateValue;

        /// <summary>
        /// Build Version FieldName.
        /// </summary>
        private static string buildVersionFieldName;

        /// <summary>
        /// Fix Description FieldName
        /// </summary>
        private static string fixDescriptionFieldName;

        /// <summary>
        /// Work Item Field Names.
        /// </summary>
        private static string workItemFieldNames;

        /// <summary>
        /// Work Item Field Values.
        /// </summary>
        private static string workItemFieldValues;

        /// <summary>
        /// Build definition that manages the build version.
        /// </summary>
        private static string buildDefinitionName;

        /// <summary>
        /// Mail Domain name.
        /// </summary>
        private static string mailDomainName;

        /// <summary>
        /// Domain name.
        /// </summary>
        private static string domainFullyQualifiedName;

        /// <summary>
        /// SMTP Server.
        /// </summary>
        private static string smtpServer;

        /// <summary>
        /// Check in Emails.
        /// </summary>
        private static string checkinEmailsAliases;

        /// <summary>
        /// CodeReview Aliases.
        /// </summary>
        private static string codeReviewAliases;

        /// <summary>
        /// Malevich Server Name.
        /// </summary>
        private static string malevichServerName;

        /// <summary>
        /// Malevich Grant Vote Permission Stored Procedure Name.
        /// </summary>
        private static string grantVotePermissionProcName;

        /// <summary>
        /// Malevich command line tool.
        /// </summary>
        private static string malevichTool;

        /// <summary>
        /// Required number of code reviewers.
        /// </summary>
        private static int requiredReviewers;

        /// <summary>
        /// Application configuration to use instead of the executable default.
        /// </summary>
        private static Configuration configuration;

        #endregion

        /// <summary>
        /// Prevents a default instance of the TfsSubmitConfig class from being created.
        /// </summary>
        private TfsSubmitConfig()
        {
            string pluginAssemblyPath = Assembly.GetExecutingAssembly().Location;
            configuration = ConfigurationManager.OpenExeConfiguration(pluginAssemblyPath);
        }

        /// <summary>
        /// Gets a value indicating whether the CodeReview feature is Enabled.
        /// </summary>
        public static bool CodeReviewEnabled
        {
            get
            {
                return codeReviewEnabled;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the Shelve feature is Enabled.
        /// </summary>
        public static bool ShelveEnabled
        {
            get
            {
                return shelveEnabled;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the ValidateChanges feature is Enabled.
        /// </summary>
        public static bool ValidateChangesEnabled
        {
            get
            {
                return validateChangesEnabled;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the SubmitChanges feature is Enabled.
        /// </summary>
        public static bool SubmitChangesEnabled
        {
            get
            {
                return submitChangesEnabled;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the disable TFS buttons is enabled.
        /// </summary>
        public static bool DisableTfsButtonsEnabled
        {
            get
            {
                return disableTfsButtonsEnabled;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the CodeCoverage validation is enabled.
        /// </summary>
        public static bool ValidateCodeCoverageEnabled
        {
            get
            {
                return validateCodeCoverage;
            }
        }

        /// <summary>
        /// Gets the Valid WorkItem State. 
        /// </summary>
        public static string ValidWorkItemState
        {
            get
            {
                return validWorkItemState;
            }
        }

        /// <summary>
        /// Gets the Resolved WorkItem State.
        /// </summary>
        public static string ResolvedWorkItemState
        {
            get
            {
                return resolvedWorkItemState;
            }
        }

        /// <summary>
        /// Gets the Resolution State FieldName.
        /// </summary>
        public static string ResolutionStateFieldName
        {
            get
            {
                return resolutionStateFieldName;
            }
        }

        /// <summary>
        /// Gets the Resolution State Value.
        /// </summary>
        public static string ResolutionStateValue
        {
            get
            {
                return resolutionStateValue;
            }
        }

        /// <summary>
        /// Gets the Build Version FieldName.
        /// </summary>
        public static string BuildVersionFieldName
        {
            get
            {
                return buildVersionFieldName;
            }
        }

        /// <summary>
        /// Gets the Fix Description FieldName.
        /// </summary>
        public static string FixDescriptionFieldName
        {
            get
            {
                return fixDescriptionFieldName;
            }
        }

        /// <summary>
        /// Gets the WorkItem Field Names.
        /// </summary>
        public static string WorkItemFieldNames
        {
            get
            {
                return workItemFieldNames;
            }
        }

        /// <summary>
        /// Gets the WorkItem Field Values.
        /// </summary>
        public static string WorkItemFieldValues
        {
            get
            {
                return workItemFieldValues;
            }
        }

        /// <summary>
        /// Gets the Build Definition Name.
        /// </summary>
        public static string BuildDefinitionName
        {
            get
            {
                return buildDefinitionName;
            }
        }

        /// <summary>
        /// Gets the Mail Domain name.
        /// </summary>
        public static string MailDomainName
        {
            get
            {
                return mailDomainName;
            }
        }

        /// <summary>
        /// Gets the Domain server.
        /// </summary>
        public static string DomainFullyQualifiedName
        {
            get
            {
                return domainFullyQualifiedName;
            }
        }

        /// <summary>
        /// Gets the SMTP Server.
        /// </summary>
        public static string SmtpServer
        {
            get
            {
                return smtpServer;
            }
        }

        /// <summary>
        /// Gets the Check in Emails.
        /// </summary>
        public static string CheckinEmailsAliases
        {
            get
            {
                return checkinEmailsAliases;
            }
        }

        /// <summary>
        /// Gets the codeReview aliases.
        /// </summary>
        public static string CodeReviewAliases
        {
            get
            {
                return codeReviewAliases;
            }
        }

        /// <summary>
        /// Gets the Malevich Server Name.
        /// </summary>
        public static string MalevichServerName
        {
            get
            {
                return malevichServerName;
            }
        }

        /// <summary>
        /// Gets the Malevich Grant Vote Permission Stored Procedure Name.
        /// </summary>
        public static string GrantVotePermissionProcName
        {
            get
            {
                return grantVotePermissionProcName;
            }
        }

        /// <summary>
        /// Gets the Malevich command line tool.
        /// </summary>
        public static string MalevichTool
        {
            get
            {
                return malevichTool;
            }
        }

        /// <summary>
        /// Gets the required number of code reviewers.
        /// </summary>
        public static int RequiredReviewers
        {
            get
            {
                return requiredReviewers;
            }
        }

        /// <summary>
        /// Loads the configuration settings with logging.
        /// </summary>
        /// <remarks>
        /// This function must be called after the global sync log session is opened.
        /// </remarks>
        internal static void LoadConfigSettings()
        {
            // Load Configuration object.
            string pluginAssemblyPath = Assembly.GetExecutingAssembly().Location;
            configuration = ConfigurationManager.OpenExeConfiguration(pluginAssemblyPath);

            string folder = Path.GetDirectoryName(pluginAssemblyPath);
            Debug.Assert(folder != null, "folder != null, folder should never be null.");

            // Load configuration settings.
            codeReviewEnabled = GetConfigBool(CodeReviewEnabledConfig, false);
            shelveEnabled = GetConfigBool(ShelveEnabledConfig, false);
            validateChangesEnabled = GetConfigBool(ValidateChangesEnabledConfig, false);
            submitChangesEnabled = GetConfigBool(SubmitChangesEnabledConfig, false);
            disableTfsButtonsEnabled = GetConfigBool(DisableTfsButtonsConfig, true);
            validateCodeCoverage = GetConfigBool(ValidateCodeCoverageConfig, false);
            validWorkItemState = GetConfigString(ValidWorkItemStateConfig, "Active");
            resolvedWorkItemState = GetConfigString(ResolvedWorkItemStateConfig, "Resolved");
            resolutionStateFieldName = GetConfigString(ResolutionStateFieldNameConfig, "ResolutionState");
            resolutionStateValue = GetConfigString(ResolutionStateValueConfig, "Fixed");
            buildVersionFieldName = GetConfigString(BuildVersionFieldNameConfig, "BuildVersion");
            fixDescriptionFieldName = GetConfigString(FixDescriptionFieldNameConfig, "FixDescription");
            workItemFieldNames = GetConfigString(WorkItemFieldNamesConfig, string.Empty);
            workItemFieldValues = GetConfigString(WorkItemFieldValuesConfig, string.Empty);
            buildDefinitionName = GetConfigString(BuildDefinitionNameConfig, "DailyBuild");
            mailDomainName = GetConfigString(MailDomainConfig, "microsoft.com");
            domainFullyQualifiedName = GetConfigString(DomainFullyQualifiedNameConfig, "redmond.corp.microsoft.com");
            smtpServer = GetConfigString(SmtpServerConfig, "smtphost.redmond.corp.microsoft.com");
            checkinEmailsAliases = GetConfigString(CheckinEmailsAliasesConfig, "tfsSubmit");
            codeReviewAliases = GetConfigString(CodeReviewAliasesConfig, "tfsSubmitCodeReview");
            malevichTool = Path.Combine(folder, GetConfigString(MalevichToolConfig, "Malevich\\Review.exe"));
            malevichServerName = GetConfigString(MalevichServerNameConfig, "MalevichDatabase");
            grantVotePermissionProcName = GetConfigString(GrantVotePermissionProcNameConfig, "GrantVotePermission");
            requiredReviewers = GetConfigInteger(RequiredReviewersConfig, 2);
        }

        /// <summary>
        /// Common parser for string values.
        /// </summary>
        /// <param name="label">Name of the configuration value.</param>
        /// <param name="defaultValue">Default value.</param>
        /// <returns>The configuration value.</returns>
        private static string GetConfigString(string label, string defaultValue)
        {
            Debug.Assert(defaultValue != null, "The defaultValue shouldn't be null.");
            string str = null;
            try
            {
                str = GetAppSetting(label);
            }
            catch (ConfigurationErrorsException)
            {
                // string remains to be 'null';
            }

            if (string.IsNullOrEmpty(str))
            {
                str = defaultValue;
            }

            return str;
        }

        /// <summary>
        /// Common parser for Boolean values.
        /// </summary>
        /// <param name="label">Name of the configuration value.</param>
        /// <param name="defaultValue">Default value.</param>
        /// <returns>The configuration value.</returns>
        private static bool GetConfigBool(string label, bool defaultValue)
        {
            // Read from the .NET app.config file
            string s = null;

            try
            {
                s = GetAppSetting(label);
            }
            catch (ConfigurationErrorsException)
            {
                // s remains to be 'null';
            }

            bool configValue;

            if (string.IsNullOrEmpty(s) ||
                (!bool.TryParse(s, out configValue)))
            {
                configValue = defaultValue;
            }

            return configValue;
        }

        /// <summary>
        /// Common parser for Integer values.
        /// </summary>
        /// <param name="label">Name of the configuration value.</param>
        /// <param name="defaultValue">Default value.</param>
        /// <returns>The configuration value.</returns>
        private static int GetConfigInteger(string label, int defaultValue)
        {
            // Read from the .NET app.config file
            string s = null;

            try
            {
                s = GetAppSetting(label);
            }
            catch (ConfigurationErrorsException)
            {
                // s remains to be 'null';
            }

            int configValue;

            if (int.TryParse(s, out configValue))
            {
                return configValue;
            }

            return defaultValue;
        }

        /// <summary>
        /// Gets the specified app setting.
        /// </summary>
        /// <param name="label">The app setting name.</param>
        /// <returns>The app setting value.</returns>
        private static string GetAppSetting(string label)
        {
            KeyValueConfigurationElement entry = configuration.AppSettings.Settings[label];
            return (entry != null) ? configuration.AppSettings.Settings[label].Value : null;
        }
    }
}
